#include "warray/warray_trig.h"
#include "test.h"

#include <iostream>

#include "custom_type.h"
#include "helper.h"

typedef boost::mpl::list< float,double > test_scalar_types;
typedef boost::mpl::list< float, double, std::complex<float>, std::complex<double> > test_complex_types;

BOOST_AUTO_TEST_CASE_TEMPLATE( array_sin, T, test_complex_types )
{
	warp::arraynd<T,1> x(warp::extents[16]);
	fill_nonzero(x);
	
	warp::arraynd<T,1> z(x.dims()); 
	warp::sin(x,z);
	BOOST_CHECK_EQUAL(x.dims(),z.dims());
	BOOST_CHECK( (array_equal(x,z,warp::detail::choose_sin<T>())) );
	
	z = warp::sin(x);
	BOOST_CHECK_EQUAL(x.dims(),z.dims());
	BOOST_CHECK( (array_equal(x,z,warp::detail::choose_sin<T>())) );
	
	z = x.copy();
	warp::sin(z,z);
	BOOST_CHECK_EQUAL(x.dims(),z.dims());
	BOOST_CHECK( (array_equal(x,z,warp::detail::choose_sin<T>())) );
}

BOOST_AUTO_TEST_CASE_TEMPLATE( array_cos, T, test_complex_types )
{
	warp::arraynd<T,1> x(warp::extents[16]);
	fill_nonzero(x);
	
	warp::arraynd<T,1> z(x.dims()); 
	warp::cos(x,z);
	BOOST_CHECK_EQUAL(x.dims(),z.dims());
	BOOST_CHECK( (array_equal(x,z,warp::detail::choose_cos<T>())) );
	
	z = warp::cos(x);
	BOOST_CHECK_EQUAL(x.dims(),z.dims());
	BOOST_CHECK( (array_equal(x,z,warp::detail::choose_cos<T>())) );
	
	z = x.copy();
	warp::cos(z,z);
	BOOST_CHECK_EQUAL(x.dims(),z.dims());
	BOOST_CHECK( (array_equal(x,z,warp::detail::choose_cos<T>())) );
}

BOOST_AUTO_TEST_CASE_TEMPLATE( array_sincos, T, test_complex_types )
{
	warp::arraynd<T,1> x(warp::extents[16]);
	fill_nonzero(x);
	
	warp::arraynd<T,1> y(x.dims()); 
	warp::arraynd<T,1> z(x.dims()); 
	warp::sincos(x,y,z);
	BOOST_CHECK_EQUAL(x.dims(),z.dims());
	BOOST_CHECK_EQUAL(x.dims(),y.dims());
	BOOST_CHECK( (array_equal(x,y,warp::detail::choose_sin<T>())) );
	BOOST_CHECK( (array_equal(x,z,warp::detail::choose_cos<T>())) );
	
	y = x.copy();
	warp::sincos(y,y,z);
	BOOST_CHECK_EQUAL(x.dims(),z.dims());
	BOOST_CHECK_EQUAL(x.dims(),y.dims());
	BOOST_CHECK( (array_equal(x,y,warp::detail::choose_sin<T>())) );
	BOOST_CHECK( (array_equal(x,z,warp::detail::choose_cos<T>())) );
	
	z = x.copy();
	warp::sincos(z,y,z);
	BOOST_CHECK_EQUAL(x.dims(),z.dims());
	BOOST_CHECK_EQUAL(x.dims(),y.dims());
	BOOST_CHECK( (array_equal(x,y,warp::detail::choose_sin<T>())) );
	BOOST_CHECK( (array_equal(x,z,warp::detail::choose_cos<T>())) );
}

BOOST_AUTO_TEST_CASE_TEMPLATE( array_cis, T, test_scalar_types )
{
	warp::arraynd<T,1> x(warp::extents[16]);
	fill_nonzero(x);
	
	warp::arraynd<std::complex<T>,1> z(x.dims()); 
	warp::cis(x,z);
	BOOST_CHECK_EQUAL(x.dims(),z.dims());
	BOOST_CHECK( (array_equal(x,z,warp::detail::cis<T>())) );
	
	z = warp::cis(x);
	BOOST_CHECK_EQUAL(x.dims(),z.dims());
	BOOST_CHECK( (array_equal(x,z,warp::detail::cis<T>())) );
}

BOOST_AUTO_TEST_CASE_TEMPLATE( array_tan, T, test_complex_types )
{
	warp::arraynd<T,1> x(warp::extents[16]);
	fill_nonzero(x);
	
	warp::arraynd<T,1> z(x.dims()); 
	warp::tan(x,z);
	BOOST_CHECK_EQUAL(x.dims(),z.dims());
	BOOST_CHECK( (array_equal(x,z,warp::detail::choose_tan<T>())) );
	
	z = warp::tan(x);
	BOOST_CHECK_EQUAL(x.dims(),z.dims());
	BOOST_CHECK( (array_equal(x,z,warp::detail::choose_tan<T>())) );
	
	z = x.copy();
	warp::tan(z,z);
	BOOST_CHECK_EQUAL(x.dims(),z.dims());
	BOOST_CHECK( (array_equal(x,z,warp::detail::choose_tan<T>())) );
}

BOOST_AUTO_TEST_CASE_TEMPLATE( array_acos, T, test_complex_types )
{
	warp::arraynd<T,1> x(warp::extents[16]);
	fill_nonzero(x);
	warp::cos(x,x);
	
	warp::arraynd<T,1> z(x.dims()); 
	warp::acos(x,z);
	BOOST_CHECK_EQUAL(x.dims(),z.dims());
	BOOST_CHECK( (array_equal(x,z,warp::detail::choose_acos<T>())) );
	
	z = warp::acos(x);
	BOOST_CHECK_EQUAL(x.dims(),z.dims());
	BOOST_CHECK( (array_equal(x,z,warp::detail::choose_acos<T>())) );
	
	z = x.copy();
	warp::acos(z,z);
	BOOST_CHECK_EQUAL(x.dims(),z.dims());
	BOOST_CHECK( (array_equal(x,z,warp::detail::choose_acos<T>())) );
}

BOOST_AUTO_TEST_CASE_TEMPLATE( array_asin, T, test_complex_types )
{
	warp::arraynd<T,1> x(warp::extents[16]);
	fill_nonzero(x);
	warp::sin(x,x);
	
	warp::arraynd<T,1> z(x.dims()); 
	warp::asin(x,z);
	BOOST_CHECK_EQUAL(x.dims(),z.dims());
	BOOST_CHECK( (array_equal(x,z,warp::detail::choose_asin<T>())) );
	
	z = warp::asin(x);
	BOOST_CHECK_EQUAL(x.dims(),z.dims());
	BOOST_CHECK( (array_equal(x,z,warp::detail::choose_asin<T>())) );
	
	z = x.copy();
	warp::asin(z,z);
	BOOST_CHECK_EQUAL(x.dims(),z.dims());
	BOOST_CHECK( (array_equal(x,z,warp::detail::choose_asin<T>())) );
}

BOOST_AUTO_TEST_CASE_TEMPLATE( array_atan, T, test_complex_types )
{
	warp::arraynd<T,1> x(warp::extents[16]);
	fill_nonzero(x);
	
	warp::arraynd<T,1> z(x.dims()); 
	warp::atan(x,z);
	BOOST_CHECK_EQUAL(x.dims(),z.dims());
	BOOST_CHECK( (array_equal(x,z,warp::detail::choose_atan<T>())) );
	
	z = warp::atan(x);
	BOOST_CHECK_EQUAL(x.dims(),z.dims());
	BOOST_CHECK( (array_equal(x,z,warp::detail::choose_atan<T>())) );
	
	z = x.copy();
	warp::atan(z,z);
	BOOST_CHECK_EQUAL(x.dims(),z.dims());
	BOOST_CHECK( (array_equal(x,z,warp::detail::choose_atan<T>())) );
}

BOOST_AUTO_TEST_CASE_TEMPLATE( array_atan2, T, test_scalar_types )
{
	warp::arraynd<T,1> x(warp::extents[16]);
	warp::arraynd<T,1> y(warp::extents[16]);
	fill_nonzero(x);
	fill_nonzero(y);
	
	warp::arraynd<T,1> z(x.dims()); 
	warp::atan2(x,y,z);
	BOOST_CHECK_EQUAL(x.dims(),z.dims());
	BOOST_CHECK( (array_equal(x,y,z,std::ptr_fun<T,T,T>(std::atan2))) );
	
	z = warp::atan2(x,y);
	BOOST_CHECK_EQUAL(x.dims(),z.dims());
	BOOST_CHECK( (array_equal(x,y,z,std::ptr_fun<T,T,T>(std::atan2))) );
	
	z = x.copy();
	warp::atan2(z,y,z);
	BOOST_CHECK_EQUAL(x.dims(),z.dims());
	BOOST_CHECK( (array_equal(x,y,z,std::ptr_fun<T,T,T>(std::atan2))) );
	
	z = y.copy();
	warp::atan2(x,z,z);
	BOOST_CHECK_EQUAL(x.dims(),z.dims());
	BOOST_CHECK( (array_equal(x,y,z,std::ptr_fun<T,T,T>(std::atan2))) );
}


